package icasue.tools.sqlhelper.core;

import icasue.tools.sqlhelper.core.SqlBuild;
import icasue.tools.sqlhelper.core.KeyUsingRate;
import lombok.Data;
import icasue.reflect.annotations.NotNull;
import icasue.reflect.annotations.Nullable;
import icasue.reflect.handles.predicate.SureOF;
import icasue.tools.sqlhelper.common.Const;


/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/9/30 上午11:40
 * @UpdateDate:
 * @Description:
 */
@Data
class SQLSplit extends SqlBuild {
    @Nullable public KeyUsingRate keyUsingRate;
    @NotNull public String column;
    @Nullable public Object[] values;
    @NotNull public SplitOP splitOP;

    SQLSplit(@NotNull SplitOP splitOP,
             @NotNull String column,
             @Nullable Object... values){
        this(splitOP,null,column,values);
    }

    SQLSplit(@NotNull SplitOP splitOP,
             @Nullable KeyUsingRate keyUsingRate,
             @NotNull String column,
             @Nullable Object... values){
        this.splitOP = splitOP;
        this.column = column;
        this.values = values;
        this.keyUsingRate = keyUsingRate;
    }


    String getSqlSegment(boolean columnStrict){
        StringBuilder segment = new StringBuilder();
        if(columnStrict){
            segment.append(Const.$STRICT).append(column).append(Const.$STRICT);
        }else {
            segment.append(column);
        }
        switch (splitOP){
            case EQ:
                SureOF.notNull(values, splitOP.error_null);
                SureOF.equals(values.length > 0, Boolean.TRUE, splitOP.error_null);
                SureOF.notNull(values[0], splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_eqItem(_formatVal(values[0])));
                break;
            case GT:
                SureOF.notNull(values, splitOP.error_null);
                SureOF.equals(values.length > 0, Boolean.TRUE, splitOP.error_null);
                SureOF.notNull(values[0], splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_eqItem(_formatVal(values[0])));
                break;
            case LT:
                SureOF.notNull(values, splitOP.error_null);
                SureOF.equals(values.length > 0, Boolean.TRUE, splitOP.error_null);
                SureOF.notNull(values[0], splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_eqItem(_formatVal(values[0])));
                break;
            case GTE:
                SureOF.notNull(values, splitOP.error_null);
                SureOF.equals(values.length > 0, Boolean.TRUE, splitOP.error_null);
                SureOF.notNull(values[0], splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_eqItem(_formatVal(values[0])));
                break;
            case LTE:
                SureOF.notNull(values, splitOP.error_null);
                SureOF.equals(values.length > 0, Boolean.TRUE, splitOP.error_null);
                SureOF.notNull(values[0], splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_eqItem(_formatVal(values[0])));
                break;
            case LIKE:
                SureOF.notNull(values, splitOP.error_null);
                SureOF.equals(values.length > 0, Boolean.TRUE, splitOP.error_null);
                SureOF.notNull(values[0], splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_likeItem(_formatVal(values[0])));
                break;
            case IN:
                segment.append(splitOP.operate_symbol)
                        .append(_range(values == null ? new Object[0] : values));
                break;
            case NOT_IN:
                segment.append(splitOP.operate_symbol)
                        .append(_range(values == null ? new Object[0] : values));
                break;
            case BETWEEN:
                SureOF.notNull(values,splitOP.error_null);
                SureOF.equals(values.length >= 2,Boolean.TRUE, "SQL segment [between] required 2 range values, but actually getting : " + values.length);
                SureOF.notNullAll(new Object[]{values[0],values[1]}, splitOP.error_null);
                segment.append(splitOP.operate_symbol)
                        .append(_between(_formatVal(values[0]), _formatVal(values[1])));
                break;
            case IS_NULL:
                segment.append(splitOP.operate_symbol);
                break;
            case IS_NOT_NULL:
                segment.append(splitOP.operate_symbol);
                break;
            default:
                break;
        }
        return segment.toString();
    }



    enum SplitOP {
        EQ(
                "SQL segment [ = ] required value not null.",
                Const.$SPACE.concat(Const.$EQ).concat(Const.$SPACE)
        ),
        GT(
                "SQL segment [ > ] required value not null.",
                Const.$SPACE.concat(Const.$GT).concat(Const.$SPACE)
        ),
        LT(
                "SQL segment [ < ] required value not null.",
                Const.$SPACE.concat(Const.$LT).concat(Const.$SPACE))
        ,
        GTE(
                "SQL segment [ >= ] required value not null.",
                Const.$SPACE.concat(Const.$GTE).concat(Const.$SPACE)
        ),
        LTE(
                "SQL segment [ <= ] required value not null.",
                Const.$SPACE.concat(Const.$LTE).concat(Const.$SPACE)
        ),
        LIKE(
                "SQL segment [ like ] required value not null.",
                Const._LIKE
        ),
        IN(
                "",
                Const._IN_
        ),
        NOT_IN(
                "",
                Const._NOT_IN_
        ),
        BETWEEN(
                "SQL segment [between] required range left and right not null.",
                Const._BETWEEN_
        ),
        IS_NULL(
                "",
                Const._IS_NULL
        ),
        IS_NOT_NULL(
                "",
                Const._IS_NOT_NULL
        );

        final String operate_symbol;
        final String error_null;
        SplitOP(String error_null, String operate_symbol){
            this.operate_symbol = operate_symbol;
            this.error_null = error_null;
        }
    }
}
